
import { Player } from '@/core/playersystem/player';
import { PhaseEnum } from '../playersystem/phase';
import { DefaultPromise, Optional } from '../util/common';

export type CardType<T extends Card> = new (...args: any[]) => T;

interface IdIncrement {
    id: number,
    getAndIncr: () => number
}

const ID: IdIncrement = {
    id: 0,
    getAndIncr(): number {
        return this.id++
    }
}

export enum Color {
    // 黑桃 ♠
    SPADE,
    // 梅花 ♣
    CLUB,
    // 红心 ♥
    HEART,
    // 方块 ♦
    DIAMOND,
    // 不代表颜色
    NOCOLOR
}

const numbersCN: string[] = ['A', '2', '3', '4', '5','6','7','8','9','10','J','Q','K']

type ColorFunc = (color: Color) => string

const colorsCN: ColorFunc = (color: Color) => {

    switch (color) {
        case Color.SPADE:
            return " ♠";
        case Color.CLUB:
            return " ♣";
        case Color.HEART:
            return " ♥";
        case Color.DIAMOND:
            return " ♦";
        case Color.NOCOLOR:
            return  "";
        default:
            return ""
    }
}

export interface CardParamsOptions {
    needUsedRecord: true
}

const defaultCardPramsOptions: CardParamsOptions = {
    needUsedRecord: true
}

export interface CardProperties {
    owner: Player | null,
    source: Player | null,
    target: Player | null,
    cancelEffect: boolean,
    canReponse: boolean,
    // 告诉gm需要重用不要回收
    reuse: boolean,
}

export interface Card {
    id: number,
    color: Color,
    number: number,
    cardProperties: CardProperties
    
    canuse: () => boolean,
    isRed: () => boolean,
    isBlack: () => boolean,
    use: () => Promise<void>,
    response: (source: Card) => Promise<Card>,
    hurtType(): HurtType,
    info: () => string,
    isBasic: () => boolean,
    numberCN: () => string,
    colorCN: () => string,
    onDrop: () => void,
    equals: (c: Card) => boolean
    getSouceCard: () => Card
}


export interface CardProxy<T extends Card> {
    name: string

    shouldApply(card: T): boolean

    apply(card: T): Card

    equals(obj: CardProxy<T>): boolean

    /**
     * 生效阶段,返回值 阶段结束时处理移除该代理 OVER代表永久有效
     */
    expirePhase(): PhaseEnum
}


export enum HurtType {
    // 普通杀
    NORMAL,
    // 雷杀
    THUNDER,
    // 火杀
    FIRE,
    
}


export class CardWrapper<T extends Card> implements Card {
    id: number
    color: Color
    number: number
    cardProperties: CardProperties
    sourceCard: T

    constructor(card: T) {
        this.color = card.color
        this.number = card.number
        this.id = card.id
        this.cardProperties = card.cardProperties
        this.sourceCard = card
    }

    hurtType(): HurtType {
        return this.sourceCard.hurtType()
    }

    isRed(): boolean {
        return this.sourceCard.isRed()
    }

    isBlack(): boolean {
        return this.sourceCard.isBlack()
    }

    isBasic(): boolean {
        return this.sourceCard.isBasic()
    }

    canuse(): boolean {
        return this.sourceCard.canuse()
    }

    async use(options=defaultCardPramsOptions): Promise<void> {
        return this.use(options)
    }

    onDrop(): void {
        this.sourceCard.onDrop()
    }

    async response(source: Card): Promise<Card> {
        return this.response(source)
    }

    info(): string {
        return this.sourceCard.info()
    }

    numberCN(): string {
        return this.sourceCard.numberCN()
    }

    colorCN(): string {
        return this.sourceCard.colorCN()
    }

    equals(c: Card) : boolean {
        return this.sourceCard.equals(c)
    }

    getSouceCard(): Card {
        return this.sourceCard.getSouceCard();
    }
}

/**
 * 基本牌
 */
export class BasicCard implements Card {
    id: number
    color: Color
    number: number
    cardProperties: CardProperties

    constructor(color: Color, number: number) {
        this.color = color
        this.number = number
        this.id = ID.getAndIncr()
        this.cardProperties = {
            owner: null,
            source: null,
            target: null,
            cancelEffect: false,
            canReponse: true,
            reuse: false
        }
    }

    /**
     * 指定距离  卡牌能作用的距离范围
     */
    specDistance(player: Player): number {
        return 999
    }

    isRed(): boolean {
        return this.color == Color.HEART || this.color == Color.DIAMOND
    }

    isBlack(): boolean {
        return this.color == Color.CLUB || this.color == Color.SPADE
    }

    isBasic(): boolean {
        return true
    }

    canuse(): boolean {
        return false
    }

    hurtType(): HurtType {
        return HurtType.NORMAL
    }

    async use(options=defaultCardPramsOptions): Promise<void> {
        if (this.cardProperties.owner) {
            const owner = this.cardProperties.owner
            const gm = this.cardProperties.owner.gameManager
            owner.handCardAreas.dropCard(this)
            gm.appendDeskCard(this)
            this.onDrop()
            gm.updateView()
        }
    }

    onDrop(options=defaultCardPramsOptions): void {
        if (this.cardProperties.owner && !this.cardProperties.reuse) {
            const gm = this.cardProperties.owner.gameManager
            gm.returnCard(this)
        }

        this.cardProperties.owner = null
        this.cardProperties.source = null
        this.cardProperties.target = null
        this.cardProperties.cancelEffect = false
        this.cardProperties.reuse = false
    }
    

    async response(source: Card): Promise<Card> {
        if (this.cardProperties.owner) {
            const owner = this.cardProperties.owner
            const gm = owner.gameManager
            owner.handCardAreas.dropCard(this)
            this.onDrop()
            gm.defineDeskCard(owner.name, this.info(), '')
        }
        return DefaultPromise(this);
    }

    info(): string {
        return this.colorCN() + this.numberCN();
    }

    numberCN(): string {
        return numbersCN[this.number-1]
    }

    colorCN(): string {
        return colorsCN(this.color)
    }

    equals(c: Card) : boolean {
        return this.id == c.id
    }

    getSouceCard(): Card {
        return this;
    }
}

/**
 * 装备牌
 */
export class Equipment implements Card {
    id: number
    color: Color
    number: number
    cardProperties: CardProperties

    constructor(color: Color, number: number) {
        this.color = color
        this.number = number
        this.id = ID.getAndIncr()
        this.cardProperties = {
            owner: null,
            source: null,
            target: null,
            cancelEffect: false,
            canReponse: true,
            reuse: false
        }
    }

    isRed(): boolean {
        return this.color == Color.HEART || this.color == Color.DIAMOND
    }

    isBlack(): boolean {
        return this.color == Color.CLUB || this.color == Color.SPADE
    }

    isBasic(): boolean {
        return false
    }

    canuse(): boolean {
        return true
    }

    hurtType(): HurtType {
        return HurtType.NORMAL
    }

    async use(): Promise<void> {
        if (this.cardProperties.owner) {
            this.cardProperties.owner.equipmentAreas.equip(this)
            this.cardProperties.owner.handCardAreas.dropCard(this)
            const gm = this.cardProperties.owner.gameManager
            gm.appendLog(`${this.cardProperties.owner.name} 装备了 ${this.info()}`)
        }
        
    }

    hasEquip(): boolean {
        if (this.cardProperties.owner) {
            return this.cardProperties.owner.equipmentAreas.hasEquip(this)
        }
        return false
    }

    onDrop(): void {
        if (this.cardProperties.owner) {
            // 在装备区丢弃的才要置空效果,手牌中丢弃的不用
            if (this.hasEquip()) {
                this.cardProperties.owner.equipmentAreas.onDrop(this)
            }
            if (!this.cardProperties.reuse) {
                const gm = this.cardProperties.owner.gameManager
                gm.returnCard(this)
            }
        }
        this.cardProperties.owner = null
        this.cardProperties.source = null
        this.cardProperties.target = null
        this.cardProperties.cancelEffect = false
        this.cardProperties.reuse = false
    }

    async response(source: Card): Promise<Card> {
        return DefaultPromise(this);
    }

    info(): string {
        return this.colorCN() + this.numberCN();
    }

    numberCN(): string {
        return numbersCN[this.number-1]
    }

    colorCN(): string {
        return colorsCN(this.color)
    }

    equals(c: Card) : boolean {
        return this.id == c.id
    }

    getSouceCard(): Card {
        return this;
    }
}

/**
 * 锦囊牌
 */
export class BrilliantCard implements Card {
    id: number
    color: Color
    number: number
    cardProperties: CardProperties

    constructor(color: Color, number: number) {
        this.color = color
        this.number = number
        this.id = ID.getAndIncr()
        this.cardProperties = {
            owner: null,
            source: null,
            target: null,
            cancelEffect: false,
            canReponse: true,
            reuse: false
        }
    }

    /**
     * 指定距离  卡牌能作用的距离范围
     */
    specDistance(player: Player): number {
        return 999
    }

    isRed(): boolean {
        return this.color == Color.HEART || this.color == Color.DIAMOND
    }

    isBlack(): boolean {
        return this.color == Color.CLUB || this.color == Color.SPADE
    }

    isBasic(): boolean {
        return false
    }

    canuse(): boolean {
        return true
    }

    hurtType(): HurtType {
        return HurtType.NORMAL
    }

    async use(): Promise<void> {
        if (this.cardProperties.owner) {
            const owner = this.cardProperties.owner
            const gm = this.cardProperties.owner.gameManager
            owner.handCardAreas.dropCard(this)
            this.onDrop()
            gm.updateView()
        }
    }

    onDrop(): void {
        if (this.cardProperties.owner && !this.cardProperties.reuse) {
            const gm = this.cardProperties.owner.gameManager
            gm.returnCard(this)
        }

        this.cardProperties.owner = null
        this.cardProperties.source = null
        this.cardProperties.target = null
        this.cardProperties.cancelEffect = false
        this.cardProperties.reuse = false
    }
    

    async response(source: Card): Promise<Card> {
        if (this.cardProperties.owner) {
            const owner = this.cardProperties.owner
            owner.handCardAreas.dropCard(this)
            this.onDrop()
        }
        return DefaultPromise(this);
    }

    info(): string {
        return this.colorCN() + this.numberCN();
    }

    numberCN(): string {
        return numbersCN[this.number-1]
    }

    colorCN(): string {
        return colorsCN(this.color)
    }

    equals(c: Card) : boolean {
        return this.id == c.id
    }

    getSouceCard(): Card {
        return this;
    }
}
